Introducción

De acuerdo con Google “la pestaña de tendencias de YouTube permite que los usuarios descubran las novedades de YouTube” [1]. Esta es una lista común compuesta de videos actuales que se muestra a todos los usuarios de un mismo país. YouTube mantiene listas de tendencias diferentes para cada país, las cuales actualiza con una frecuencia de 15 minutos. Si bien Google no ha hecho público el método para calcular las listas de tendencias, ha comunicado que buscan seleccionar videos que representen la actualidad de YouTube y sean relevantes para los usuarios del país correspondiente. Algunos de los factores que tienen en cuenta son:

En base a estos criterios, es posible que se encuentren videos con bajas visitas en posiciones altas de la lista, si estas se comparan con otros videos de la misma lista.

El conjunto de datos seleccionado, YouTube Trending Video Dataset (updated daily) contiene la información de estas listas de tendencias de 11 países: Brasil, Canadá, Alemania, Francia, Gran Bretaña, India, Japón, Corea del sur, México, Rusia y Estados Unidos. Algunos de los datos que incluye son el título del video, la fecha de subida del video, la cantidad de likes y de visitas, etc. El conjunto de datos es actualizado con una frecuencia diaria y se agregan hasta 200 videos nuevos en las listas de tendencias por día. Se utilizará la versión 610 del conjunto de datos, la cual contiene datos actualizados hasta el día 7 de Abril de 2022.

El creador de este conjunto de datos propone algunos usos:

Añadiendo a estas propuestas, puede resultar interesante el estudio de estos datos para encontrar todo tipo de relaciones entre los datos de cada video y el entorno de YouTube, por ejemplo:

Otra área que resulta interesante explorar es automatizar la generación de alguno de los atributos del conjunto de datos, como la miniatura, el título o la descripción. Finalmente, la predicción del rendimiento de un video (visualizaciones, likes, dislikes) es otra razón que hace interesante el estudio de este conjunto de datos.

Análisis exploratorio del conjunto de datos

Los datos a analizar corresponden a los trendings de YouTube para el país de México, separado en dos dataset, uno que corresponde al principal, y un segundo dataset con información de las categorías disponibles para cada video.

Se comenzará cargando el dataset principal a un dataframe:

mx_dataset <- read.csv("./dataset/MX_youtube_trending_data.csv", encoding = "UTF-8")
head(mx_dataset, n = 20)

Las dimensiones del dataset son, 121.399 filas y 16 columnas.

dim(mx_dataset)
## [1] 121399     16

Una versión resumida del dataset se encuentra a continuación, en este resumen se indican:

summary(mx_dataset)
##    video_id            title           publishedAt         channelId        
##  Length:121399      Length:121399      Length:121399      Length:121399     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  channelTitle         categoryId    trending_date          tags          
##  Length:121399      Min.   : 1.00   Length:121399      Length:121399     
##  Class :character   1st Qu.:10.00   Class :character   Class :character  
##  Mode  :character   Median :22.00   Mode  :character   Mode  :character  
##                     Mean   :18.69                                        
##                     3rd Qu.:24.00                                        
##                     Max.   :29.00                                        
##    view_count            likes             dislikes      comment_count    
##  Min.   :        0   Min.   :       0   Min.   :     0   Min.   :      0  
##  1st Qu.:   378754   1st Qu.:   19048   1st Qu.:   123   1st Qu.:    898  
##  Median :   850201   Median :   53161   Median :   546   Median :   2289  
##  Mean   :  2249624   Mean   :  160530   Mean   :  2323   Mean   :  11988  
##  3rd Qu.:  2089202   3rd Qu.:  146047   3rd Qu.:  1712   3rd Qu.:   6136  
##  Max.   :278080610   Max.   :16213758   Max.   :879359   Max.   :6817451  
##  thumbnail_link     comments_disabled  ratings_disabled   description       
##  Length:121399      Length:121399      Length:121399      Length:121399     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
## 

El dataset usado, en ocasión del primer hito, corresponde a mx_dataset, el cual encapsula los videos más tendenciosos de YouTube en la región de México. Este dataset contiene, 121399 filas de información, dónde cada fila corresponde a los datos de un video que fue considerado para su captura debido a que estuvo en tendencia en algún momento de su existencia. Las columnas del dataset corresponde a:

unique(mx_dataset)

A continuación se cargará un segundo dataset asociado al anterior que contiene la información de las categorías de los videos:

library(jsonlite)
mx_list_categories <- fromJSON("./dataset/MX_category_id.json")
mx_categories <- data.frame(mx_list_categories)
head(mx_categories, n= 20)

El archivo MX_category_id.json contiene las categorías (categoryId) a la que puede pertenecer cada uno de los videos. Las columnas de este archivo son las siguientes:

Las dimensiones de este dataset son, 31 filas y 6 columnas.

dim(mx_categories)
## [1] 31  6

La columna items.snippet del dataset de categorías es de tipo data.frame, es decir, cada fila del conjunto contiene otro data.frame en el valor de la columna items.snippet.

class(mx_categories$items.snippet)
## [1] "data.frame"
head(mx_categories$items.snippet)

En total este dataset contiene 30 categorías, a continuación se listan todas las categorías:

unique(mx_categories$items.snippet$title)
##  [1] "Film & Animation"     "Autos & Vehicles"     "Music"               
##  [4] "Pets & Animals"       "Sports"               "Short Movies"        
##  [7] "Travel & Events"      "Gaming"               "Videoblogging"       
## [10] "People & Blogs"       "Comedy"               "Entertainment"       
## [13] "News & Politics"      "Howto & Style"        "Education"           
## [16] "Science & Technology" "Movies"               "Anime/Animation"     
## [19] "Action/Adventure"     "Classics"             "Documentary"         
## [22] "Drama"                "Family"               "Foreign"             
## [25] "Horror"               "Sci-Fi/Fantasy"       "Thriller"            
## [28] "Shorts"               "Shows"                "Trailers"

El dataset mx_dataset contiene valores nulos o en blanco en las columna description y tags. Se encontraron 6819 valores faltantes en la columna description y 20407 en la columna tags.

null_values_dataset <- sapply(mx_dataset, function(x) is.na(x) | x == "" | x == "[None]")
colSums(null_values_dataset)
##          video_id             title       publishedAt         channelId 
##                 0                 0                 0                 0 
##      channelTitle        categoryId     trending_date              tags 
##                 0                 0                 0             20407 
##        view_count             likes          dislikes     comment_count 
##                 0                 0                 0                 0 
##    thumbnail_link comments_disabled  ratings_disabled       description 
##                 0                 0                 0              6819

El dataset mx_categories no contiene valores nulos o en blanco en ninguna de sus columnas. Esto incluye las columnas que se encuentran dentro del dataframe de la columna items.snippet.

sapply(mx_categories, function(x) any(is.na(x) | x == ""))
##          kind          etag    items.kind    items.etag      items.id 
##         FALSE         FALSE         FALSE         FALSE         FALSE 
## items.snippet 
##         FALSE

grafico de cantidad de videos por categoria

library(ggplot2)
aux_categories <- data.frame(categoryId = mx_categories$items.id , categoryTitle = mx_categories$items.snippet$title)
mx_categories <- merge(mx_dataset, aux_categories)

ggplot(mx_categories, aes(x = categoryTitle)) +
  geom_bar(stat = 'count') +
  coord_flip() +
  xlab("Categoria") + ylab("Cantidad de videos")

grafico de dispersion de la cantidad de visitas vs cantidad de likes

ggplot(mx_dataset, aes(x = view_count, y = likes)) +
  geom_point() +
  xlab("Cantidad de visitas") + ylab("Cantidad de likes")

grafico de dispersion de cantidad de visitas vs cantidad de dislikes

ggplot(mx_dataset, aes(x = view_count, y = dislikes)) +
  geom_point() +
  xlab("Cantidad de visitas") + ylab("Cantidad de dislikes")

grafico de dispersion de cantidad de visitas vs cantidad de comentarios

ggplot(mx_dataset, aes(x = view_count, y = comment_count)) +
  geom_point() +
  xlab("Cantidad de visitas") + ylab("Cantidad de comentarios")

gráfico de top 10 canales con mas videos en la lista de trendings

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v tibble  3.1.6     v dplyr   1.0.8
## v tidyr   1.2.0     v stringr 1.4.0
## v readr   2.1.2     v forcats 0.5.1
## v purrr   0.3.4
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter()  masks stats::filter()
## x purrr::flatten() masks jsonlite::flatten()
## x dplyr::lag()     masks stats::lag()
top_10 <- group_by(mx_dataset, channelTitle) |>
  summarize(Freq = n()) |>
  arrange(desc(Freq)) |>
  top_n(10)
## Selecting by Freq
top_10
ggplot(top_10, aes(x = reorder(channelTitle, Freq), y = Freq)) +
  geom_bar(stat = 'identity') +
  coord_flip() +
  xlab('Canal de YouTube') +
  ylab('Cantidad de videos en trendings')

grafico de acumulacion de cantidad de likes y dislikes del top 10 canales con mas videos en trendings

library(gridExtra)
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
library("scales")
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
top_10_accumulations <- group_by(mx_dataset, channelTitle) |>
  summarize(Freq = n(), likes = sum(likes), dislikes = sum(dislikes)) |>
  arrange(desc(Freq)) |>
  top_n(10, Freq)

likes_plot <- ggplot(top_10_accumulations,aes(x = reorder(channelTitle, Freq),y = likes)) + 
  geom_bar(stat = 'identity') + 
  coord_flip() +
  scale_y_continuous(labels = scales::comma, breaks = c(0, 245000000, 490000000, 735000000, 980000000)) +
  xlab("Canal") + ylab("Cantidad de likes")

dislikes_plot <- ggplot(top_10_accumulations,aes(x = reorder(channelTitle, Freq),y = dislikes)) + 
  geom_bar(stat = 'identity') + 
  coord_flip() +
  scale_y_continuous(labels = scales::comma) +
  xlab("Canal") + ylab("Cantidad de dislikes")


grid.arrange(likes_plot, dislikes_plot)

grafico de top 10 canales con mayor acumulacion de likes

likes_accumulation <- group_by(mx_dataset, channelTitle) |>
  summarize(Accumulation = sum(likes)) |>
  arrange(desc(Accumulation)) |>
  top_n(10)
## Selecting by Accumulation
ggplot(likes_accumulation, aes(x = reorder(channelTitle, Accumulation), y = Accumulation)) +
  geom_bar(stat = 'identity') +
  coord_flip() +
  xlab('Canal de YouTube') +
  ylab('Cantidad de videos en trendings')

matriz de correlación entre columnas

library(corrplot)
## corrplot 0.92 loaded
mx_dataset$comments_disabled <- as.numeric(as.logical(mx_dataset$comments_disabled))
mx_dataset$ratings_disabled <- as.numeric(as.logical(mx_dataset$ratings_disabled))

numeric_mx_dataset <- Filter(is.numeric, mx_dataset)
numeric_mx_dataset.cor <- cor(numeric_mx_dataset)
corrplot(numeric_mx_dataset.cor, method = 'number')

# mx_dataset <- read.csv("./dataset/MX_youtube_trending_data.csv", encoding = "UTF-8")
# mx_dataset$country <- "MX"
# us_dataset <- read.csv("./dataset/US_youtube_trending_data.csv", encoding = "UTF-8")
# us_dataset$country <- "US"
# br_dataset <- read.csv("./dataset/BR_youtube_trending_data.csv", encoding = "UTF-8")
# br_dataset$country <- "BR"
# ca_dataset <- read.csv("./dataset/CA_youtube_trending_data.csv", encoding = "UTF-8")
# ca_dataset$country <- "CA"
# de_dataset <- read.csv("./dataset/DE_youtube_trending_data.csv", encoding = "UTF-8")
# de_dataset$country <- "DE"
# fr_dataset <- read.csv("./dataset/FR_youtube_trending_data.csv", encoding = "UTF-8")
# fr_dataset$country <- "FR"
# gb_dataset <- read.csv("./dataset/GB_youtube_trending_data.csv", encoding = "UTF-8")
# gb_dataset$country <- "BG"
# in_dataset <- read.csv("./dataset/IN_youtube_trending_data.csv", encoding = "UTF-8")
# in_dataset$country <- "IN"
# jp_dataset <- read.csv("./dataset/JP_youtube_trending_data.csv", encoding = "UTF-8")
# jp_dataset$country <- "JP"
# kr_dataset <- read.csv("./dataset/KR_youtube_trending_data.csv", encoding = "UTF-8")
# kr_dataset$country <- "KR"
# ru_dataset <- read.csv("./dataset/RU_youtube_trending_data.csv", encoding = "UTF-8")
# ru_dataset$country <- "RU"
 
# dataset <- rbind(mx_dataset, us_dataset, br_dataset, ca_dataset, de_dataset, fr_dataset, gb_dataset, in_dataset, jp_dataset, kr_dataset, ru_dataset)

cantidad de videos en trending por pais

# videos_amount <- group_by(dataset, country) |>
#   summarize(amount = n())
 
# ggplot(videos_amount, aes(x = country, y = amount)) +
#   geom_bar(stat = 'identity') +
#   scale_y_continuous(labels = scales::comma) +
#   coord_flip() +
#   xlab("Pais") + ylab("Cantidad de videos")

cantidad de visitas de todos los videos en la lista de trendings por pais

# view_count <- group_by(dataset, country) |>
#   summarize(views = sum(view_count))
 
# ggplot(view_count, aes(x = country, y = views)) +
#   geom_bar(stat = 'identity') +
#   scale_y_continuous(labels = scales::comma) +
#   xlab("Pais") + ylab("Cantidad de visitas")

Preguntas y problemas

Repositorio GitHub

El proyecto se documenta en un repositorio de GitHub, donde se podrá acceder en el siguiente link:

Repositorio de Github

Referencias

[1] https://support.google.com/youtube/answer/7239739?hl=es-419